为便于使用,本节中的命令按字母顺便编排,若该命令只在JRockit R27或R28的某个版本得到支持,则会在标题旁注明版本信息,否则表示这两个版本均支持该命令。
在JRockit R27中,与该命令相对应的是checkjrarecording。该命令用于检查JFR引擎的状态,更多有关JFR的内容,请参见第8章和第9章的内容。一般情况下,该命令至少会返回一条当前正在进行的记录任务,因为大部分版本的R28在运行的时候都会开启一个低消耗的记录人物。由于JRockit JVM中可能同时存在多个正在执行的记录任务,因此可以为该命令指定一个任务ID,以便获取目标任务的执行状态。如果不指定参数,或者参数值为-1,则会返回所有正在执行的任务的状态。除了指定任务ID外,还可以通过参数name来指定记录任务的名字。如果是持续型记录任务,可以将参数name设置为continuous里查找。
例如:
C:\>jrcmd 6328 check_flightrecording name=continuous verbose=true
6328:
Recording : id=0 name="continuous" duration=0s (running)
http://www.oracle.com/jrockit/jvm/:
java/alloc/accumulated/thread : disabled period=1000
java/alloc/accumulated/total : enabled period=0
java/alloc/object/in_new_tla : disabled threshold=10000000
java/alloc/object/outside_tla : disabled threshold=10000000
java/exception/stats : enabled period=1000
java/exception/throw : disabled period=1000
java/file/read : disabled threshold=10000000
java/file/write : disabled threshold=10000000
java/monitor/enter : disabled threshold=10000000
java/monitor/profile : disabled period=1000
java/monitor/wait : disabled threshold=10000000
java/socket/read : disabled threshold=10000000
java/socket/write : disabled threshold=10000000
java/thread/end : enabled period=0
java/thread/park : disabled threshold=10000000
java/thread/sleep : disabled threshold=10000000
java/thread/start : enabled period=0
vm/class/load : disabled threshold=10000000
vm/class/memory/free : enabled threshold=0
如果将参数verbose的值设为false,则只会在简单列出记录任务的ID、名字和持续时间;而设为true后,则会像示例一样,列出记录任务的事件生产者,以及每个事件生产者的的事件类型。上面的示例中列出了激活的持续型记录,其ID为0。在http://www.oracle.com/jrockit/jvm/中列出了各种类型的事件生产者,可以作为参考。
译者注,链接已死。
参见
start_flightrecordingstop_flightrecording和dump_flightrecording命令的说明。
该命令通常与startjrarecording命令一起使用,用于检查JRockit JVM中是否已经存在正在执行中的记录任务。若是JRA中已经有记录任务正在执行,则会列出该任务的设置参数。下面的示例是启动JRA记录任务9秒钟之后的执行checkjrarecording命令的结果:
C:\>jrcmd 5516 checkjrarecording
5516:
JRA is running a recording with the following options:
filename=D:\myrecording.jra, recordingtime=120s, methodsampling=1,
gcsampling=1, heapstats=1, nativesamples=0, methodtraces=1,
sampletime=5,zip=1, hwsampling=0, delay=0s, tracedepth=64
threaddump=1, threaddumpinterval=0s, latency=1,
latencythreshold=20ms, cpusamples=1, cpusampleinterval=1s
The recording was started 9 seconds ago.
There are 111 seconds left of the recording.
上面示例中的记录任务是通过startjrarecording命令启动的。
参见
startjrarecording和stopjrarecording命令的说明。译者注,
stopjrarecording命令在本书中并未找到相关说明内容,https://community.oracle.com/thread/690864?start=0&tstart=0和JRocki JRCMD中有简单的说明,请自取。
有时候,需要检查JRockit JVM的启动设置。比如,当JVM的垃圾回收器行为比较奇怪时,可以使用该命令来检查相关的参数配置,又或者使用该命令查看随JVM一起启动的代理(agent)的配置。
该命令会列出JVM的启动参数,只不过在这里列出的是实际传递给JVM的参数,以及那些隐式传给JVM的参数。如下所示:
C:\>jrcmd 2416 command_line
2416:
Command Line: -Denv.class.path=.;C:\Program Files\
Java\jre6\lib\ext\QTJava.zip -Dapplication.home=C:\jrockits\R28.0.0_
R28.0.0-547_1.6.0 -client -Djrockit.ctrlbreak.enableforce_crash=true
-Dsun.java.launcher=SUN_STANDARD com.jrockit.mc.rcp.start.MCMain
-Xmx512m -Xms64m -Xmanagement:port=4712,ssl=false,authenticate=false
该命令用于在不中断记录任务的情况下,获取记录内容,因而可以获取持续性记录任务的内容。其基本实现是,克隆目标任务,暂停该克隆后的记录任务,再将之写入到硬盘中。
如用方式如下所示:
C:\>jrcmd 7420 dump_flightrecording recording=0
copy_to_file=my_continuous_snapshot.jfr.gz compress_copy=true
在上面的示例中,通过命令指示JRCMD完成对编号为0的记录任务进行转储为本地文件my_continous_snapshot.jfr.gz。一般情况下,编号为0的是持续性记录任务,会一直在JVM中运行。当然,也可以通过参数name来指定要转储的记录任务,例如name=continuous。设置参数compress_copy为true时,会将转储文件以gzip进行压缩。
参见
startjrarecordingstopjrarecording和check_flightrecording命令的说明。
heap_diagnostics命令用于获取JVM中堆的详细信息,包括内存使用情况和引用对象使用情况等信息。执行该命令时,会触发一次full gc来收集相关信息。该命令不接受其他参数。
输出信息包含3个部分。
第一部分是系统信息,包括可用内存总量和堆内存总量。如下所示:
C:\>jrcmd 7420 heap_diagnostics
7420:
Invoked from diagnosticcommand
======== BEGIN OF HEAPDIAGNOSTIC =========================
Total memory in system: 3706712064 bytes
Available physical memory in system: 1484275712 bytes
-Xmx (maximal heap size) is 1073741824 bytes
Heapsize: 65929216 bytes
Free heap-memory: 8571400 bytes
第2部分是 Detailed Heap Statistics,基本上与print_object_summary命令的输出相同,但不包含 points-to信息。这里会列出系统中所有类型的相关信息,因此输出内容会很长:
heap_diagnostics命令后,当前类型的实例占用堆内存大小的变化值,单位为KB;第五列是类型名。
--------- Detailed Heap Statistics: --------- 25.9% 3179k 37989 +0k [C 9.6% 1178k 2210 +0k [I 7.4% 912k 38943 +0k java/lang/String 7.4% 906k 265 +0k [B 6.2% 764k 6994 +0k java/lang/Class ...
12257kB total ---
--------- End of Detailed Heap Statistics ---
第3部分是引用对象统计信息(Reference Object statistics),即引用对象使用情况的详细信息,例如弱引用。引用对象信息也是按照类型进行划分的,在每种类型下,列出了当前类型实例所指向的其他类型。如下所示:
null的实例的实例的数量。第七列和最后一列是引用对象所指向的类型。
----- Reference Objects statistics separated per class -----
Total Reach Act PrevAct Null
----- ----- --- ------- ----
Soft References:
637 81 0 4 552 Total for all Soft References
java/lang/ref/SoftReference =>
559 7 0 0 552 Total
552 0 0 0 552 => null
2 2 0 0 0 => [Ljava/lang/reflect/Constructor;
1 1 0 0 0 => org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader
1 1 0 0 0 => [Ljava/lang/String;
1 1 0 0 0 => java/util/jar/Manifest
1 1 0 0 0 => java/lang/StringCoding$StringDecoder
1 1 0 0 0 => sun/font/FileFontStrike
java/util/ResourceBundle$BundleReference =>
44 42 0 2 0 Total
31 31 0 0 0 => java/util/ResourceBundle$1
11 11 0 0 0 => java/util/PropertyResourceBundle
2 0 0 2 0 => null
org/eclipse/core/internal/registry/ReferenceMap$SoftRef =>
21 20 0 1 0 Total
20 20 0 0 0 =>
org/eclipse/osgi/framework/internal/core/BundleHost
1 0 0 1 0 => null
sun/misc/SoftCache$ValueCell =>
1 0 0 1 0 Total
1 0 0 1 0 => null
Weak References:
3084 2607 0 236 241 Total for all Weak References
java/lang/ref/WeakReference =>
1704 1463 0 0 241 Total
765 765 0 0 0 => java/lang/String
330 330 0 0 0 => java/lang/Class
241 0 0 0 241 => null
Phantom References:
6 6 0 0 0 Total for all Phantom References
java/lang/ref/PhantomReference =>
6 6 0 0 0 Total
5 5 0 0 0 => java/lang/Object
1 1 0 0 0 => sun/dc/pr/Rasterizer
Cleared Phantom:
9 9 0 0 0 Total for all Cleared Phantom
jrockit/vm/ObjectMonitor =>
9 9 0 0 0 Total
2 2 0 0 0 =>
org/eclipse/osgi/framework/eventmgr/EventManager$EventThread
1 1 0 0 0 => java/util/TaskQueue
Finalizers:
197 197 0 0 0 Total for all Finalizers
88 88 0 0 0 => java/util/zip/ZipFile
55 55 0 0 0 => java/util/zip/Inflater
18 18 0 0 0 => java/awt/Font
14 14 0 0 0 => java/lang/ClassLoader$NativeLibrary
Weak Handles:
12309 12309 0 0 0 Total for all Weak Handles
9476 9476 0 0 0 =>
org/eclipse/osgi/internal/baseadaptor/DefaultClassLoader
1850 1850 0 0 0 => java/lang/String
Soft reachable referents not used for at least 198.332 s cleared. 4 SoftReferences were soft alive but not reachable
(when found by the GC),
0 were both soft alive and reachable, and 633 were not soft alive.
----- End of Reference Objects statistics ----- ======== END OF HEAPDIAGNOSTIC ==========================
从这个示例中可以看到,大部分弱引用对象都指向String类的实例。弱引用对象是指由java.lang.ref.WeakReference实例引用的对象。在示例中系统中,共有3084个弱引用,其中2067个处于可达状态。另外,在示例中可以看到,软引用对象指向的对象至少存活了198秒。
对于粗粒度的对象引用分析和堆使用率分析来说,heap_diagnostics命令是非常有用的。当然,使用JFR或Memleak Tool可以更简便的实现同样功能。
参见
print_object_summary命令的说明。
有时候,需要将堆内存转储到本地文件以便做离线分析。到JRockit R28版本时,JRockit可以生成HPROF格式的堆转储文件,这样就可以使用其他支持HPROF格式的工具(例如Eclipse Memory Analyzer Tool)做离线分析了。
使用方式如下所示:
C:\>jrcmd 7772 hprofdump filename=mydump.hprof
segment_threshold=2G segment_size=1G
7772:
Wrote dump to mydump.hprof
译者注:HRPOF的介绍,参见https://docs.oracle.com/javase/7/docs/technotes/samples/hprof.html
使用参数segment_threshold和segment_size可以将转储文件分割为几个较小的文件。在上面的示例中,当JVM堆超过2G时,会以1G为大小分割为多个转储文件。
注意,只有在工具支持Java PROFILE 1.0.2 HPROF格式的转储文件时,才能使用参数
segment_size和segment_threshold。
生成的转储文件会放到JROCKIT_HOME目录下,如果不指定文件名的话,会以时间戳来命名文件,如下所示:
C:\>jrcmd 7772 hprofdump
7772:
Wrote dump to heapdump_Tue_Sep_22_19_09_16_2009
该命令用于关闭外部管理服务器(exter management server)。曾经,因为存在一些问题,导致以"stop"开头的命令会终止对 ctrlhandler.act文件的解析,于是就没有将关闭管理服务器的命令命名为 "stop_management_server""。
使用该命令时无需添加额外的参数,如下所示:
C:\>jrcmd 7772 kill_management_server
7772:
某些JVM参数可以通过类似–XX:<Flag>=<value>的形式来设置。在第1章中曾经介绍过,这里参数成为VM参数,可以通过命令list_vmflags列出这些参数。
如下所示:
C:\>jrcmd 7772 list_vmflags describe=true alias=true
Global:
UnlockDiagnosticVMOptions = false (default, writeable)
- Enable processing of flags relating to field diagnostics
UnlockInternalVMOptions = false (default)
- Enable processing of internal, unsupported flags
Class:
FailOverToOldVerifier = true (default, writeable)
- Fail over to old verifier when split verifier fails
UseVerifierClassCache = true (default)
- Try to cache java.lang.Class lookups for old verifier.
UseClassGC = true (default)
(Alias: -Xnoclassgc)
- Allow GC of Java classes
...
Threads:
UseThreadPriorities = false (default)
- Use native thread priorities
DeferThrSuspendLoopCount = 4000 (default, writeable)
- Number of iterations in safepoint loop until we try blocking
...
由于VM参数非常多,因此在上面的示例中只列出了其中的一部分,其中某些VM参数是可以在运行过程中通过set_vmflag命令动态设置,而另外一些则只能在启动时设置。
对于高端用户来说,可以在启动JVM时,设置参数
-XX:UnlockInternalVMOptions=true以开启对JVM内存参数的访问。不过,风险自负。参见
set_vmflag命令。
只有当JVM开启了锁分析(使用JVM参数-XX:UseLockProfiling=true或-XX:UseNativeLockProfiling=true,参见第4章的相关内容)时,该命令才会生效,它会打印出锁分析的相关内容。
C:\>jrcmd 1442 lockprofile_print
1442:
Class, Lazy Banned, Thin Uncontended, Thin Contended, Lazy Reservation,
Lazy lock, Lazy Reverted, Lazy Coop-Reverted, Thin Recursive, Fat
Uncontended, Fat Contended, Fat Recursive, Fat Contended Sleep,
Reserve Bit Uncontended, Reserve Bit Contended
[B, false, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/Thread, false, 11, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/security/Permissions, false, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/util/Hashtable, false, 0, 0, 34, 524, 1, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/Class, false, 0, 0, 24, 77, 2, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/Object, false, 1, 0, 11, 139572, 1, 0, 0, 1, 0, 0, 0, 6, 0
java/lang/StringBuffer, false, 0, 0, 137, 773, 0, 0, 0, 0, 0, 0, 0, 0, 0
sun/nio/cs/StandardCharsets,
false, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/util/Properties, false, 0, 0, 5, 479, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/ThreadGroup, false, 0, 0, 3, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/ref/Reference$ReferenceHandler,
false, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
sun/security/provider/Sun,
false, 0, 0, 39, 5589, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/io/PrintStream, false, 0, 0, 7, 7818, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/net/URL, false, 0, 0, 70, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/io/ByteArrayInputStream,
false, 0, 0, 47, 1115, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/util/logging/Logger, false, 0, 0, 2, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0
jrockit/vm/CharBufferThreadLocal,
false, 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0
java/security/Provider$Service,
false, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/Runtime, false, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/lang/reflect/Field, false, 0, 0, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0
java/util/Random, false, 0, 0, 6, 18556549, 1, 0, 0, 0, 0, 0, 0, 0, 0
参见lockprofile_reset命令。
只有当JVM开启了锁分析(使用JVM参数-XX:UseLockProfiling=true或-XX:UseNativeLockProfiling=true,参见第4章的相关内容)时,该命令才会生效,它会重置当前锁分析计数器的值为0。
参见lockprofile_print命令。
该命令用于启动/关闭 Memory Leak Server(MLS)。JRockit Meomory Leak Detector使用MLS作为本地服务器来通信。正常情况下,MLS会通过JMX自行启动,但某些情况下,不得不手动开启MLS。例如,可能只想启动MLS,而不启动JMX代理(JMX agent),此时就可以使用memleakserver命令来控制MLS的生命周期,其就像一个开关一样,再执行一次就可以关闭MLS。
The following example starts the MLS on port 7899: 下面的命令在开启MLS时,指定端口为7899:
C:\>jrcmd 5516 memleakserver port=7899
5516:
Memleak started at port 7899.
再执行一次,MLS就会关闭:
C:\>jrcmd 5516 memleakserver port=7899
5516:
Stopping the server does not produce any output.
参见
hprofdump命令。
该命令是JRockit R28版本中heap_diagnostics命令的别名
有时候,需要查看JVM是否载入了某个类。例如,某个SPI框架使用了动态类载入功能,当它执行失败时,需要查找出某些类是否已经被载入过了。其中一种方案是转储出所有已载入的类,然后使用grep命令来查找指定的类。使用print_class_summary命令就可以很方便的转储出所有的类。如下所示:
C:\>jrcmd 5516 print_class_summary
5516:
- Class Summary Information starts here
class java/lang/Object
*class java/util/Vector$1
*class sun/util/calendar/CalendarUtils
*class sun/util/calendar/ZoneInfoFile$1
*class sun/util/calendar/ZoneInfoFile
*class sun/util/calendar/TzIDOldMapping
*class java/util/TimeZone$1
*class java/util/TimeZone
**class java/util/SimpleTimeZone
**class sun/util/calendar/ZoneInfo
*class sun/util/calendar/CalendarDate
**class sun/util/calendar/BaseCalendar$Date
***class sun/util/calendar/Gregorian$Date
*class sun/util/calendar/CalendarSystem
**class sun/util/calendar/AbstractCalendar
***class sun/util/calendar/BaseCalendar
****class sun/util/calendar/Gregorian
...
在上面的示例中,输出的类是按照各自的继承关系来排序,并使用星号来标识继承深度。下面的示例则展示了在类Unix系统上如何查找具体的类型:
$ jrcmd 5516 print_class_summary | grep LoadAnd
*class LoadAndDeadlock
**class LoadAndDeadlock$LockerThread
**class LoadAndDeadlock$AllocThread
该命令用于显示代码生成队列的长度和当前JVM中的优化队列。使用参数list来控制是否显示队列的内容。如下所示:
C:\>jrcmd 1442 print_codegen_list list=true
1442:
-------------------------------------------------------
format: <position> <directive no> <method description>
strategies: q=quick, n=normal, o=optimize
JIT queue: 0 methods in queue
OPT queue:
0: 1 java/math/BigDecimal.<init>(Ljava/math/BigInteger;JII)V
1: 1 java/math/BigDecimal.add(Ljava/math/BigDecimal;)Ljava/math/BigDecimal;
2: 1 java/lang/String.<init>([C)V
3: 1 java/util/TreeMap$NavigableSubMap.size()I
4: 1 java/util/TreeMap$NavigableSubMap.setLastKey()V
5: 1 jrockit/vm/Strings.compare(Ljava/lang/String;Ljava/lang/String;)I
6: 1 com/sun/org/apache/xerces/internal/dom/CharacterDataImpl.setNodeValueInternal(Ljava/lang/String;Z)V
7: 1 com/sun/org/apache/xerces/internal/dom/CoreDocumentImpl.changed()V
8: 1 java/lang/String.getChars(II[CI)V
9: 1 com/sun/org/apache/xerces/internal/dom/NodeImpl.appendChild(Lorg/w3c/dom/Node;)Lorg/w3c/dom/Node;
10: 1 spec/jbb/Warehouse.getAddress()Lspec/jbb/Address;
11: 1 jrockit/vm/ArrayCopy.copy_checks_done2(Ljava/lang/Object;ILjava/lang/Object;II)V
12 methods in queue
正如之前章节中介绍的,除了Java堆之外,JRockit还将内存用于其他地方。有时候,若Java堆占用了太多内存,则JRockit则可能会没有足够的本地内存(native memory)使用。命令print_memusage可以用于查看JRockit是如何使用系统内存的。如下所示:
C:\>jrcmd 484536 print_memusage
484536:
[JRockit] memtrace is collecting data...
[JRockit] *** 0th memory utilization report
(all numbers are in kbytes)
Total mapped ;;;;;;;1298896
; Total in-use ;;;;;; 438768
;; executable ;;;;; 28460
;;; java code ;;;; 5952; 20.9%
;;;; used ;;; 5647; 94.9%
;; shared modules (exec+ro+rw) ;;;;; 35912
;; guards ;;;;; 528
;; readonly ;;;;; 25936
;; rw-memory ;;;;; 376392
;;; Java-heap ;;;; 262144; 69.6%
;;; Stacks ;;;; 3472; 0.9%
;;; Native-memory ;;;; 110775; 29.4%
;;;; java-heap-overhead ;;; 8206
;;;; codegen memory ;;; 896
;;;; classes ;;; 43008; 38.8%
;;;;; method bytecode ;; 4477
;;;;; method structs ;; 3895 (#83104)
;;;;; constantpool ;; 18759
;;;;; classblock ;; 1596
;;;;; class ;; 3041 (#8403)
;;;;; other classdata ;; 8280
;;;;; overhead ;; 34
;;;; threads ;;; 24; 0.0%
;;;; malloc:ed memory ;;; 22647; 20.4%
;;;;; codeinfo ;; 1231
;;;;; codeinfotrees ;; 429
;;;;; exceptiontables ;; 125
;;;;; metainfo/livemaptable ;; 5883
;;;;; codeblock structs ;; 2
;;;;; constants ;; 14
;;;;; livemap global tables ;; 994
;;;;; callprof cache ;; 0
;;;;; paraminfo ;; 146 (#1979)
;;;;; strings ;; 8376 (#148622)
;;;;; strings(jstring) ;; 0
;;;;; typegraph ;; 2009
;;;;; interface implementor list ;; 40
;;;;; thread contexts ;; 19
;;;;; jar/zip memory ;; 5378
;;;;; native handle memory ;; 19
;;;; unaccounted for memory ;;; 36017; 32.5%;1.59
---------------------!!!
从上面的示例中可以看到,JRockit进程保留了1GB多的内存空间自用,看起来有点多,但实际上,JRockit只用了429MB。此外,Java堆已经使用了约60%的空间。
该命令的结果以树形显示,每个分配节点都有其子节点,例如"malloc:ed memory"表示JVM内部的结构,包括活动对象图(livemap),类型图(type graph)等等。最右侧的百分比数值表示当前节点占父节点的百分比。顶层节点并不计算百分比,之前提到Java堆大约已经使用了60%是手工计算得出的,即262,144/438,768 * 100 = 59.7%。
该命令还可用来追踪本地内存发生的内存泄漏,例如使用JVMTI开发的本地代理中出现的内存泄漏。
与该命令的R27版本类似,print_memusage在R28版本中仍旧用于查看JRockit对内存的使用,不过在以往的基础上做了些改进。
在排查OOM问题时,该命令非常有用。正如第10章中介绍的,很多时候,内存泄漏往往是无意中持有废弃对象造成的,但有的时候,造成内存泄漏的原因可能多种多样,例如本地资源管理不善等,具体来说,可能是因为打开的java.util.zip.GZIPOutputStreams实例数量超过了限制,类载入器持有了太多的类,或第三方JNI代码中造成的内存泄漏。
例如:
C:\>jrcmd 7772 print_memusage
7772:
Total mapped 1281284KB (reserved=1002164KB)
- Java heap 1048576KB (reserved=932068KB)
- GC tables 35084KB
- Thread stacks 11520KB (#threads=27)
- Compiled code 5696KB (used=5490KB)
- Internal 840KB
- OS 67712KB
- Other 48048KB
- JRockit malloc 29184KB (malloced=27359KB #275574)
- Native memory tracking 1024KB (malloced=537KB #11)
- Java class data 33600KB (malloced=33471KB #41208)
第一列是内存空间的名字,第二列是该内存空间所占用的内存大小,第三列是与内存空间相关的详细信息。在上面的示例中可以到,Java heap占用了内存的绝大部分空间,当然,这是正常情况。
在追踪本地内存泄漏问题是,通常需要查看内存使用量随时间的变化情况。使用参数baseline可以开启比较分析。
参数scale用于修改显示单位,默认为KB。
例如,将显示单位改为MB:
C:\>jrcmd 7772 print_memusage scale=M baseline
7772:
Total mapped 1252MB (reserved=978MB)
- Java heap 1024MB (reserved=910MB)
- GC tables 34MB
- Thread stacks 11MB (#threads=27)
- Compiled code 5MB (used=5MB)
- Internal 0MB
- OS 66MB
- Other 47MB
- JRockit malloc 28MB (malloced=26MB #275601)
- Native memory tracking 1MB (malloced=0MB #11)
- Java class data 32MB (malloced=32MB #41208)
参数baseline用于执行差异化分析,会显示出在基线时间之后发生的内存使用量变化。
C:\>jrcmd 7772 print_memusage scale=M
7772:
Total mapped 1282MB +30MB (reserved=984MB +6MB)
- Java heap 1024MB (reserved=910MB)
- GC tables 34MB
- Thread stacks 14MB +3MB (#threads=35 +8)
- Compiled code 6MB +1MB (used=6MB)
- Internal 0MB
- OS 70MB +4MB
- Other 49MB +2MB
- JRockit malloc 41MB +13MB (malloced=34MB +8MB #330019 +54418)
- Native memory tracking 2MB (malloced=1MB #21 +10)
- Java class data 38MB +6MB (malloced=38MB +6MB #48325 +7117)
从上面的示例中可以看出,在设置了baseline参数后,进程额外使用了30MB内存,其中的6MB被保留了下来。此外,多开了8个线程,JRockit也多分配了8MB内存。现在,JRockit本地堆工分配了330019字节内存,比之前增加了54418字节,因而多使用了13MB的虚拟内存。
malloc object是在JVM内部使用类似于
malloc系统调用分配到的内存。例如,像下面的代码这样就会在本地堆上创建一个 malloc object对象,并增加 malloc object对象的个数。void * foo = malloc(512);类似的,调用free(foo)方法会将 malloc object数量减一。
若要重置baseline参数,不再进行比较的话,可以使用reset参数:
C:\>jrcmd 7772 print_memusage reset
使用参数trace_alloc_sites=1可以开启对本地内存分配点的追踪,设置参数trace_alloc_sites=0则可禁用之。若想追踪所有的本地内存分配点,包括JVM启动时的内存分配,将环境变量TRACE_ALLOC_SITES设置为1即可。
在开启分配点追踪后,会根据level参数的值来显示内存分配的详细信息。如果同时设置了baseline参数,则只会显示发生变化的内存分配点。例如:
C:\>jrcmd 5784 print_memusage level=1
5784:
Total mapped 1300092KB +25040KB (reserved=1090888KB -7496KB)
- Java heap 1048576KB (reserved=1008068KB -11020KB)
- GC tables 35084KB
- Thread stacks 14336KB +3840KB (#threads=32 +9)
- Compiled code 4928KB +1152KB (used=4774KB +1209KB)
- Internal 1416KB +256KB
- OS 83040KB +2048KB
- Other 50312KB +2448KB
- JRockit malloc 27200KB +7424KB (malloced=25807KB +6236KB #266150 +63919)
balance 44KB +9KB (#23 +5)
breakpoints 9KB -8KB (#37 -255)
breaktable 8KB +2KB (#13 +3)
codealloc 56KB +25KB (#1037 +502)
codeblock 143KB +39KB (#2567 +686)
codeinfo 1224KB +351KB (#22300 +6404)
codeinfotree 400KB +126KB (#74 +18)
dynarray 116KB +30KB (#2058 +392)
finalhandles 3KB +2KB (#14 +7)
hashtable 32KB +32KB (#5 +3)
implchange 982KB +354KB (#20920 +7556)
javalock 279KB +266KB (#4477 +4092)
libcache 245KB +47KB (#9473 +1840)
libconstraints 22KB +3KB (#464 +75)
lifecycle 14KB +4KB (#33 +9)
livemap_system 1083KB +305KB (#25117 +5207)
memleak_trends 544KB +544KB (#5809 +5809)
memleakserver 96KB +96KB (#2906 +2906)
metainfo 7669KB +1916KB (#21935 +6416)
在上面的示例中,JRockit Mission Control Memleak工具监视了命令调用,可以看到Memleak自身分配了一些本地内存。将日志级别调为4,可以看到更详细的内容:
C:\>jrcmd 5784 print_memusage level=4
5784:
Total mapped 1310708KB +35656KB (reserved=1083664KB -14720KB)
- Java heap 1048576KB (reserved=1002572KB -16516KB)
- GC tables 35084KB
108KB
+32KB (#27 +8)
update_trends memleak_trends.c: 364 592KB
+592KB (#3612 +3612)
update_trends memleak_trends.c: 365 84KB
+84KB (#3612 +3612)
create_id_from_object memleakserver.c: 170 25KB
+25KB (#1 +1)
create_id_from_classp memleakserver.c: 217 116KB
最后,使用参数displayMap可以让print_memusage命令显示出各个JVM子系统的内存使用情况:
C:\>jrcmd 5784 print_memusage displayMap
5784:
Total mapped 1311220KB +36168KB (reserved=1083664KB -14720KB)
- Java heap 1048576KB (reserved=1002572KB -16516KB)
- GC tables 35084KB
- Thread stacks 14592KB +4096KB (#threads=33 +10)
- Compiled code 5824KB +2048KB (used=5634KB +2069KB)
- Internal 1160KB
- OS 83180KB +2188KB
- Other 52660KB +4796KB
- JRockit malloc 30464KB +10688KB (malloced=29618KB +10047KB #302842 +100611)
- Native memory tracking 2112KB +1088KB (malloced=1035KB +582KB #672 +308)
- Java class data 37568KB +11264KB (malloced=37537KB +11243KB #45413 +14104)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
CODE Compiled code rwx 0x0000000007ef0000 (128KB)
...
MSP JRockit malloc (179/266) rw 0x0000000008150000 (64KB)
THREAD Stack 6952 rwx 0x0000000008d80000 (12KB)
...
INT TLA memcache rw 0x000000000e330000 (64KB)
HEAP Java heap rw 0x0000000010040000 (46004KB)
HEAP Java heap reserved 0x0000000012d2d000.(1002572KB)
OS *awt.dll r x 0x000000006d0b1000
...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Lowest accessible address 00010000
Highest accessible address 7FFEFFFF
Amount free virtual memory 786016KB
6 free vm areas in range 4KB - 8KB totalling > 24KB
7 free vm areas in range 8KB - 16KB totalling > 76KB
24 free vm areas in range 16KB - 32KB totalling >528KB
281 free vm areas in range 32KB - 64KB totalling > 15MB
3 free vm areas in range 64KB - 128KB totalling >236KB
9 free vm areas in range 128KB - 256KB totalling > 1MB
5 free vm areas in range 256KB - 512KB totalling > 1MB
7 free vm areas in range 512KB - 1MB totalling > 4MB
8 free vm areas in range 1MB - 2MB totalling > 11MB
2 free vm areas in range 2MB - 4MB totalling > 4MB
5 free vm areas in range 4MB - 8MB totalling > 30MB
1 free vm areas in range 8MB - 16MB totalling > 11MB
5 free vm areas in range 16MB - 32MB totalling >103MB
1 free vm areas in range 32MB - 64MB totalling > 51MB
1 free vm areas in range 64MB - 128MB totalling > 67MB
1 free vm areas in range 128MB - 256MB totalling >135MB
1 free vm areas in range 256MB - 512MB totalling >326MB
正如示例那样,内存块被划分为以下几类:
该命令用于堆中每个类型所占用的内存,因此可以将之作为一个简版的内存泄漏检测工具使用。当然,JRockit Mission Control Memory Leak Detector比该命令强大得多,但在某些场景下,使用该命令更加合适。例如,由于安全策略限制,无法开启MLS(参见第10章相关内容),此时就可以通过该命令完成相关操作。
print_object_summary命令会打印出堆中实例的直方图,按照每种类型统计其实例所占用的内存空间,以及从上一次执行命令之后实例占用内存的增量值。
C:\>jrcmd 6328 print_object_summary
6328:
--------- Detailed Heap Statistics: ---------
22.1% 2697k 34813 +2697k [C
14.3% 1744k 373 +1744k [B
14.2% 1736k 3220 +1736k [Ljava/lang/Object;
11.8% 1443k 2177 +1443k [I
6.9% 839k 35833 +839k java/lang/String
5.6% 682k 6240 +682k java/lang/Class
2.6% 314k 13429 +314k java/util/HashMap$Entry
2.0% 242k 3218 +242k [Ljava/util/HashMap$Entry;
1.2% 149k 3185 +149k java/util/HashMap
1.0% 126k 5406 +126k java/util/Hashtable$Entry
0.9% 106k 2844 +106k [Ljava/lang/String;
0.8% 98k 1396 +98k java/lang/reflect/Field
0.5% 65k 844 +65k java/lang/reflect/Method
0.5% 64k 190 +64k [S
12192kB total ---
--------- End of Detailed Heap Statistics ---
The output contains one line per class that has instances on the heap. 输出内容中按照每种类型统计了内存使用的相关数据。
在列出类型名时,使用的是正式的Java描述符格式。更多相关信息,请参见Java语言规范。
正常情况下,该命令只会列出占用内存0.5%以上的类型。修改参数cutoff的值可以调整输出结果,将百分比乘以1000作为参数值即可。
还可以使用print_object_summary命令玩些花样。就上面的示例来说,可以使用参数"points-to"找出到底是哪些实例指向了字符数组。最多可以指定8个不同的"points-to"参数,有时候会简单粗暴的将参数名设置为name1到name8,再指定具体的参数值就可以列出指向这些类型的内存使用信息。
在下面的示例中,列出了指向字符数组和字符串的、内存占用大于0.1%的实例的内存使用信息:
C:\>jrcmd 6352 print_object_summary cutoffpointsto=100 name1=[C name2=java/lang/String
--------- Detailed Heap Statistics: ---------
42.0% 10622k 116820 +0k [C
11.3% 2851k 121648 +0k java/lang/String
6.0% 1520k 3676 +0k [Ljava/util/HashMap$Entry;
4.1% 1033k 18906 +12k org/eclipse/core/internal/registry/ReferenceMap$SoftRef
3.5% 890k 38001 +0k java/util/HashMap$Entry
3.2% 800k 7323 +0k java/lang/Class
3.0% 747k 19820 +0k [Ljava/lang/String;
2.9% 741k 10063 +0k [I
2.9% 738k 15765 +0k org/eclipse/core/internal/registry/ConfigurationElement
2.8% 699k 15469 +0k [Ljava/lang/Object;
1.1% 284k 262 +0k [B
1.0% 241k 4411 +1k org/eclipse/osgi/internal/resolver/ExportPackageDescriptionImpl
0.7% 173k 7408 +0k org/osgi/framework/Version
0.7% 171k 3653 +0k java/util/HashMap
0.6% 148k 734 +0k [Ljava/util/Hashtable$Entry;
0.5% 129k 2 +0k [Lorg/eclipse/core/internal/registry/ReferenceMap$IEntry;
25273kB total ---
[C is pointed to from:
99.6% 121713 java/lang/String
0.2% 270 [[C
java/lang/String is pointed to from:
37.2% 98288 [Ljava/lang/String;
15.6% 41274 java/util/HashMap$Entry
11.9% 31530 org/eclipse/core/internal/registry/ConfigurationElement
7.2% 19067 [Ljava/lang/Object;
--------- End of Detailed Heap Statistics ---
从上面的示例可以看出,大部分字符数组都有被字符串对象引用的,而字符串对象又主要是被字符好对象引用的。这很正常。
该命令通常用于查看堆中实例的分布情况,此外,也可以追踪指定类型的内存使用增量信息,配置"points-to"参数更有利于查找内存泄漏问题。不过,查找内存泄漏问题,还是Memleak更加强大,具体用哪个,依赖于具体的场景。
改命令用于输出JRockit的属性信息,包括启动JVM时的初始属性,专用于JRockit JVM的属性,以及当前系统属性。这三部分信息分开输出,,如下所示:
C:\>jrcmd 6012 print_properties
6012:
=== Initial Java properties: ===
java.vm.specification.name=Java Virtual Machine Specification
java.vm.vendor.url.bug=http://edocs.bea.com/jrockit/go2troubleshooting.html
java.home=D:\demos_3.1\jrmc_3.1\jre
java.vm.vendor.url=http://www.bea.com/
java.vm.specification.version=1.0
file.encoding=Cp1252
java.vm.info=compiled mode
...
=== End Initial Java properties ===
=== VM properties: ===
jrockit.alloc.prefetch=true
jrockit.alloc.redoprefetch=true
jrockit.vm=D:\demos_3.1\jrmc_3.1\jre\bin\jrockit\jvm.dll
jrockit.alloc.pfd=448
jrockit.alloc.pfl=64
jrockit.alloc.cs=512
jrockit.vm.dir=D:\demos_3.1\jrmc_3.1\jre\bin\jrockit
jrockit.alloc.cleartype=0
=== End VM properties ===
=== Current Java properties: ===
java.vm.vendor.url.bug=http://edocs.bea.com/
jrockit/go2troubleshooting.html
java.runtime.name=Java(TM) 2 Runtime Environment, Standard Edition
sun.boot.library.path=D:\demos_3.1\jrmc_3.1\jre\bin
java.vm.version=R27.6.3-40_o-112056-1.5.0_17-20090318-2104-windows-ia32
java.vm.vendor=BEA Systems, Inc.
java.vendor.url=http://www.bea.com/
path.separator=;
java.vm.name=BEA JRockit(R)
file.encoding.pkg=sun.io
user.country=SE
...
=== End Current Java properties ===
输出的结果中可能会包含重复属性设置,因为某些属性可能会同时存在于 initial和 current部分的内容中。
JVM堆SIGQUIT信号的默认处理就是打印线程调用栈信息。市面上有很多可以分析线程调用栈信息的工具,不过最好用的仍旧是Latency Analysis和JFR。此外,JRockit Management Console也可以做一些简单的分析工作,甚至能检测死锁。
命令的输入内容如下所示:
C:\>jrcmd 7420 print_threads
7420:
===== FULL THREAD DUMP ===============
Mon Sep 28 00:08:56 2009
Oracle JRockit(R) R28.0.0-547-121310-1.6._14-20090918-2121-windows-ia32
"Main Thread" id=1 idx=0x4 tid=7776 prio=6 alive, in native
at org/eclipse/swt/internal/win32/OS.WaitMessage( )Z
(Native Method)[optimized]
at org/eclipse/swt/widgets/Display.sleep(Display.java:4220)[inlined]
at org/eclipse/ui/application/ WorkbenchAdvisor.eventLoopIdle
(WorkbenchAdvisor.java:364)[optimized]
at org/eclipse/ui/internal/Workbench.runEventLoop(Workbench.java:2385)
at ...
-- end of trace
"State Data Manager" id=13 idx=0x38 tid=7596
prio=5 alive, sleeping, native_waiting, daemon
at java/lang/Thread.sleep(J)V(NativeMethod)[optimized]
at org/eclipse/osgi/internal/baseadaptor/StateManager.run(StateManager.java:297)
at java/lang/Thread.run(Thread.java:619)
at jrockit/vm/RNI.c2java(IIIII)V(Native Method)[optimized]
-- end of trace
...
"JFR request timer" id=34 idx=0x84 tid=2624
prio=5 alive, waiting, native_blocked, daemon
-- Waiting for notification on: java/util/TaskQueue@0x1202F238[fat lock]
at jrockit/vm/Threads.waitForNotifySignal(JLjava/lang/Object;)Z(Native Method)[optimized]
at java/lang/Object.wait(J)V(Native Method)
at java/lang/Object.wait(Object.java:485)
at java/util/TimerThread.mainLoop(Timer.java:483)
^-- Lock released while waiting: java/util/TaskQueue@0x1202F238[fat lock]
at java/util/TimerThread.run(Timer.java:462)
at jrockit/vm/RNI.c2java(IIIII)V(Native Method)[optimized]
-- end of trace
===== END OF THREAD DUMP ===============
默认情况下,该命令不会打印线程调用栈中调用本地方法的栈帧,若想输出这部分内容,需要添加参数nativestack=true。此外,若想在输出内容中加上有关java.util.concurrent包中锁实现的相关信息,需要添加参数concurrentlocks=true。
该命令用于打印出JVM中所有的UTF-8常量,例如类名,方法和字符串常量。
下面的示例中列出了常量池中所有的URL:
$ jrcmd 3824 print_utf8pool | grep http
"http://www.w3.org/TR/xinclude": refs=2, len=29
"http://apache.org/xml/properties/internal/
symbol-table": refs=12, len=54
其中,refs是指向该常量的引用的数目,len指的是以字节计算的常量值得长度。
该命令用于打印JVM的状态,其格式与JRockit宕机时生成的转储文件类似。如下所示:
C:\>jrcmd 7420 print_vm_state
7420:
Uptime : 0 days, 02:35:53 on Tue Sep 22 19:14:39 2009
Version : Oracle JRockit(R) R28.0.0-547-121310-1.6.0_14-20090918-2121-windows-ia32
CPU : Intel Core 2 SSE SSE2 SSE3 SSSE3 SSE4.1 Core Intel64
Number CPUs : 2
Tot Phys Mem : 3706712064 (3534 MB)
OS version : Microsoft Windows Vista version 6.0 Service Pack 2(Build 6002) (32-bit)
Thread System : Windows Threads
Java locking : Lazy unlocking enabled (class banning) (transfer banning)
State : JVM is running
Command Line : -Denv.class.path=.;C:\Program Files\Java\jre6\lib\ext\QTJava.zip -Dapplication.home=C:\jrockits\R28.0.0_R28.0.0-547_1.6.0 -client -XX:UnlockInternalVMOptions=true -Dsun.java.launcher=SUN_STANDARD com.jrockit.mc.rcp.start.MCMain
java.home : C:\jrockits\R28.0.0_R28.0.0-547_1.6.0\jre
j.class.path : C:\jrockits\R28.0.0_R28.0.0-547_1.6.0/missioncontrol/mc.jar
j.lib.path : C:\jrockits\R28.0.0_R28.0.0-
...
StackOverFlow : 0 StackOverFlowErrors have occured
OutOfMemory : 0 OutOfMemoryErrors have occured
C Heap : Good; no memory allocations have failed
GC Strategy : Mode: pausetime, with strategy: singleconcon(basic strategy : singleconcon)
GC Status : OC is not running. Last finished OC was OC#369.
Heap : 0x10040000 - 0x17207000 (Size: 113 MB)
Compaction : (no compaction area)
CompRefs : References are 32-bit.
Loaded modules:
0000000000400000-000000000043afff C:\jrockits\R28.0.0_R28.0.0-547_1.6.0\bin\jrmc.exe
0000000077d30000-0000000077e56fff C:\Windows\system32\ntdll.dll
00000000763f0000-00000000764cbfff C:\Windows\system32\kernel32.dll
0000000077a30000-0000000077accfff C:\Windows\system32\USER32.dll
0000000077400000-000000007744afff C:\Windows\system32\GDI32.dll
0000000077ea0000-0000000077f65fff C:\Windows\system32\ADVAPI32.dll
...
00000000764e0000-00000000765a2fff C:\Windows\system32\RPCRT4.dll
000000006d3e0000-000000006d3fefff C:\jrockits\R28.0.0_R28.0.0-547_1.6.0\jre\bin\java.dll
输出内容与JVM状态相关,例如版本、锁、线程、路径、载入的模块和动态库等。
参见
heap_diagnostics命令。
正如在第2章中介绍的,在可以在启动JVM时,通过指导文件为JVM优化管理器提供相关参数。此外,还可以在运行时通过run_optfile命令来动态添加相关参数,通过参数filename指定所需的指导文件。需要注意的是,R27和R28版本所支持的指导文件的格式有些区别。此外,对于R27版本来说,由于指导文件并没有正式的说明文档,因此可能只会在通过JRockit官方支持时才会用到它。
R28版本中的run_optfile命令可以接收多个参数,其中最重要的仍然是filename,用于指定指导文件。R28版本中,指导文件依旧没有正式说明文档,其具体格式可能会在后续的版本中发生变化。在第2章中,介绍了有关指导文件相关内容,只不过还不完整。
run_optfile命令还可以按指定策略重新编译指定的方法。
在下面的示例中,会按照优化编译策略,重新编译jav.util.ArrayList#get方法。
C:\>jrcmd 7736 run_optfile method=java.util.ArrayList.get*
strategy=opt disass=false
该命令用于强制JVM执行java.lang.System#runFinalization方法,即提示运行时应该要运行某些对象的finalize方法了。
该命令用于强制执行一次full gc。
强制执行垃圾回收是非常少见的案例,因为JVM本身可以决定什么时候该进行垃圾回收。如果用户干预这个过程,则反倒可能会降低执行性能。但在某些场景下,显式调用垃圾回收方法是有用处的。例如,通过详细的垃圾回收日志来查看内存使用和存活对象集。
使用该命令时,若不添加参数,则默认只会执行年轻代垃圾回收(nursery collection),而不会对堆做内存整理操作。若要触发一次full gc,则需要添加参数full=true。如下所示:
C:\>jrcmd 4748 runsystemgc full=true
4748:
该命令不会返回任何信息。
该命令用于设置JVM参数。如下所示:
C:\>jrcmd 7772 set_vmflag flag=DumpOnCrash value=false
7772:
成功执行后,该命令不会返回任何信息。若是对只读参数执行写操作,会返回错误信息,如下所示:
C:\>jrcmd 7772 set_vmflag flag=DisableAttachMechanism value=true
7772:
Not a writeable flag "DisableAttachMechanism"
若想修改那些在运行时不可修改的JVM参数,需要在启动JVM时,通过类似-XX:<Flag>=<value>形式的语法来设置参数。
参见`list_vmflags命令。
start_flightrecording命令用于启动JFR记录任务,可以是持续性任务或计时任务。使用JROCKIT_HOME/jre/lib/jfr目标下的命名模板文件(JSON格式),可以对记录任务做具体配置。
C:\>jrcmd 7420 start_flightrecording name=MyRecording settings=jra.jfs duration=30s filename=my_recording.jfr.gz compress=true
7420:
Started recording 5
在上面的示例中,通过命令名,使用jra.jfs模板开启了一个持续30秒的记录任务,记录结束后,会在JROCKIT_HOME目录下,生成一个名为my_recording.jfr.gz`的、压缩过的记录文件。
使用check_flightrecording命令可以在记录开始后检查记录任务的执行情况:
C:\>jrcmd 7420 check_flightrecording
7420:
Recording : id=0 name="continuous" duration=0s (running)
Recording : id=5 name="MyRecording" duration=30s dest="my_recording.jfr.gz" compress=true (running)
在30秒过后,记录任务的状态会从running变为stopped,并生成记录文件。
有些模板只能是附加的,即它们必须和其他基础模板一起使用,这类模板在其文件开头的注释信息中做了说明。如果注释信息以 "Additional settings"开头,则说明它是附加模板。使用方式如下所示:
C:\>jrcmd 7420 start_flightrecording name=DefaultAndLocks settings=default.fls settings=lock.fls duration=30s filename=defaultAndLocks.jfr.gz compress=true
就操作JFR来说,最简单的方式还是使用JRockit Mission Control客户端。更多有关JFR的信息,请参见第9章的内容。
压缩文件可能会带来些额外的开销,但会降低文件大小。
参见
check_flightrecording`dump_flightrecording和stop_flightrecording。
该命令用于在没有启动脚本重启JVM的情况下,开启外部管理代理(external management agent)。其具体实现与使用-Xmanagement参数开启管理代理相同。
启动应用程序服务器,部署J2EE应用程序可能需要花费相当长的时间,而且JVM"热身"又需要花费一段时间,因此,若是在启动JVM忘记添加参数配置是很闹心的。如果是生产环境的服务器,重启就更麻烦了。
在下面的示例中,通过该命令在4711端口开启了一个外部管理代理,关闭了SSL和身份教研,开启了自动发现(JDP)。需要注意的是,这里提前配置好password.properties文件和密钥文件。更多详细内容,请参见Oracle Sun Developer Network中有关 Monitoring and Management Using JMX Technology的内容。
C:\>jrcmd 473528 start_management_server ssl=false authenticate=false port=4711 autodiscovery=true
2416:
该命令在执行成功后,不会返回任何信息。
start_management_server命令总是会启动一个本地管理代理(local management agent),而在开启本地代理之后,就不能被关闭了。
操作JRA记录,最好是通过JRockit Mission Control客户端。更多有关这方面的信息,请参见第8章的内容.
不过在某些场景下,可能无法使用JRockit Mission Control客户端,例如环境不允许使用JMX连接,或者使用的JDK 1.4版本等等。这时,就该startjrarecording命令出场了。在下面的示例中,通过命令行在进程号5516的JRockit进程中开启了一个JRA记录任务,任务持续2分钟,在30秒之后开始记录。
在对使用了大量框架,或使用了企业容器(例如WebLogic)的应用程序做采样时,调用栈通常都很深。这时需要通过配置参数,来调整采样信息。
参数sampletime用于指定线程采样的频率。由于示例中采样的持续时间很短,因此将采样频率设置为5毫米一次。同时,开启对延迟事件的记录。
C:\>jrcmd 5516 startjrarecording filename=C:\myrecording.jra recordingtime=120 delay=30 tracedepth=64 sampletime=5 latency=true
5516:
JRA recording started.
开始执行命令后,JVM会在控制台开始打印如下相关内容:
[INFO ][jra ] Delaying JRA recording for 30 seconds.
[INFO ][jra ] Starting JRA recording with these options:
filename=D:\myrecording.jra, recordingtime=120s, methodsampling=1,
gcsampling=1, heapstats=1, nativesamples=0, methodtraces=1,
sampletime=5, zip=1, hwsampling=0 delay=30s, tracedepth=64
threaddump=1, threaddumpinterval=0s, latency=1,
latencythreshold=20ms, cpusamples=1, cpusampleinterval=1s
在记录结束后,JVM会打印类似下面的内容:
[INFO ][jra ] Zipped the recording file.
[INFO ][jra ] Finished recording. Results written to
C:\myrecording.jra.
该命令用于终止进行中的JFR记录任务,目标任务可以通过参数name或recording来指定。如下所示:
C:\>jrcmd 7420 stop_flightrecording recording=10
7420:
默认情况下,会针对被终止的记录任务生成转储文件。如果不想保留记录数据,可以添参数discard=true。终止任务时,会将目标记录从check_flightrecording命令的输出列表中移除,因此可以使用该命令清理不再需要的记录任务。
参见命令
check_flightrecordingdump_flightrecording和start_flightrecording。
该命令用于打印时间戳,并显示出JVM已经运行的持续时间。
C:\>jrcmd 6012 print_properties
6012:
==== Timestamp ==== uptime: 0 days, 00:04:39 time:
Sun Jan 24 15:47:42 2010
该命令用于控制JRockit中的日志模块,它可以针对某个子系统调整日志级别,重定向日志输出,以及调整日志输出内容。执行该命令时,若不添加额外参数,则会列出当前所有日志模块。
C:\demos_3.1>jrcmd 4504 verbosity
4504:
Current logstatus:
jrockit : level=WARN, decorations=201, sanity=NONE
memory (gc) : level=WARN, decorations=201, sanity=NONE
nursery (yc) : level=WARN, decorations=201, sanity=NONE
model : level=WARN, decorations=201, sanity=NONE
devirtual : level=WARN, decorations=201, sanity=NONE
codegen (code) : level=WARN, decorations=201, sanity=NONE
native (jni) : level=WARN, decorations=201, sanity=NONE
thread : level=WARN, decorations=201, sanity=NONE
opt : level=WARN, decorations=201, sanity=NONE
具体输出内容中,每行的第一个单词是模块名,圆括号中的是模块的别名。
下面的示例中,启用了代码生成器模块(参见第2章内容)的常规输出,其具体效果,与启动JVM时添加-Xverbose:codegen参数相同。
C:\demos_3.1>jrcmd 5556 verbosity set=codegen=INFO
5556:
Current logstatus:
jrockit : level=WARN, decorations=201, sanity=NONE
memory (gc) : level=WARN, decorations=201, sanity=NONE
nursery (yc) : level=WARN, decorations=201, sanity=NONE
model : level=WARN, decorations=201, sanity=NONE
devirtual : level=WARN, decorations=201, sanity=NONE
codegen (code) : level=INFO, decorations=201, sanity=NONE
正如示例中所展现的,verbosity命令列出了新的日志状态。
verbosity命令还可用于做异常分析,找出异常是在何处抛出的。
在R28版本之前,那时JFR还不能做异常分析,唯一的方法就是查日志,在启动JVM时,添加参数-Xverbose:exceptions(参见第5章相关内容)。
下面的示例展示了如何开启/关闭异常分析,以及如何调整输出内容。若将参数decorations置空,则默认会调整时间戳、模块名和进程号的输出。
C:\>jrcmd 6064 verbosity set=exceptions=info decorations=module
6064:
Current logstatus:
之后,若目标JVM进程抛出异常,则会打印信息 "Throw me!"。
[excepti] ExceptionThrowerException: Throw me!
[excepti] ExceptionThrowerException: Throw me!
将日志级别设置为debug后,JRockit会显示出异常的调用栈:
D:\>jrcmd 6064 verbosity set=exceptions=debug decorations=module
6064:
Current logstatus:
其效果与启动JVM时添加-Xverbose:exceptions=debug相同:
[excepti] ExceptionThrowerException: Throw me!
at jrockit/vm/Reflect.fillInStackTrace0(Ljava/lang/Throwable;)V(Native Method)
at java/lang/Throwable.fillInStackTrace()Ljava/lang/Throwable;(Native Method)
at java/lang/Throwable.<init>(Throwable.java:196)
at java/lang/Exception.<init>(Exception.java:41)
at ExceptionThrowerException.<init>(ExceptionThrowerException.java:5)
at ExceptionThrower.throwMe(ExceptionThrower.java:24)
at ExceptionThrower.doStuff(ExceptionThrower.java:20)
at ExceptionThrower.loop(ExceptionThrower.java:11)
at ExceptionThrower.main(ExceptionThrower.java:4)
at jrockit/vm/RNI.c2java(IIIII)V(Native Method)
--- End of stack trace
这样就可以在生产环境中队日志进行配置了。在异常分析完成后,可以将日志级别还原回原来的设置,不会产生额外的执行开销。
该命令用于在不重启应用程序服务器的情况下查看JRockit的具体版本。例如,已经将JRockit JVM注册为系统服务,没有控制台可用,就可以通过该命令查看JRockit JVM的具体版本信息。使用该命令时,无需添加额外参数。
C:\>%JAVA_HOME%\bin\jrcmd 2416 version
2416:
BEA JRockit(R) (build R27.6.2-20_o-108500-1.6.0_05-20090120-1116-windows-ia32, compiled mode)